﻿using System;
using System.Collections.Generic;
using System.Linq;

using System.Data.Entity;
using System.Data.EntityClient;
using System.Data.EntityModel;
using System.Data.Entity.ModelConfiguration;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using System.Data.Objects.DataClasses;
using System.Reflection;
using System.Xml;
using System.Data.Objects;
using System.Data.Common;
using System.Data;
using System.Xml.XPath;
using System.Xml.Serialization;
using System.Text;
using System.Windows.Threading;

using GTServices.Entities;

namespace GTServices.Model
{
    public class DatabaseContext : DbContext
    {

        public const string SQLCEConntectionString = @"Persist Security Info=True;Data Source={0}";

        //Core Tables
        public DbSet<Category> Categories { get; set; }

        public DbSet<Pattern> Patterns { get; set; }
        public DbSet<FileExtension> FileExtensions { get; set; }
       
        public DbSet<Language> Languages { get; set; }
        public DbSet<Template> Templates { get; set; }
        public DbSet<Classification> Classifications { get; set; }

        private DatabaseContext()
            : base()
        {
            this.Configuration.LazyLoadingEnabled = false;
            this.Configuration.ProxyCreationEnabled = false;
        }

        public DatabaseContext(String fileName, string databaseName = "GrepTool", bool seedData = false)
            : base(String.Format(SQLCEConntectionString, System.IO.Path.GetFullPath(fileName)))
        {
            this.Configuration.LazyLoadingEnabled = false;
            this.Configuration.ProxyCreationEnabled = false;
            //EnsureDatabase(fileName);
            if (!System.IO.File.Exists(fileName))
            {
                var seedInit = new DatabaseContextInitializer();
                seedInit.InitializeDatabase(this); 
            }
            if (seedData)
            {
                if (this.Database.Exists())
                {
                    this.Database.Delete(); 
                }
                var seedInit = new DatabaseContextInitializer();
                seedInit.InitializeDatabase(this); 
            }
            ReloadData();
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<Category>()
                         .HasMany<Pattern>(i => i.Patterns)
                         .WithMany(p => p.Categories)
                         .Map(c =>
                         {
                             c.MapLeftKey("IssueId");
                             c.MapRightKey("PatternId");
                             c.ToTable("IssuePatterns");
                         });
            
            modelBuilder.Entity<Language>()
                       .HasMany<FileExtension>(l => l.FileExtensions)
                       .WithMany(fe => fe.Languages)
                       .Map(c =>
                       {
                           c.MapLeftKey("LanguageId");
                           c.MapRightKey("FileExtensionId");
                           c.ToTable("LanguageExtensions");
                       });   
            
        }
        public bool EnsureDatabase(string fileName)
        {

            if (!System.IO.File.Exists(fileName))
            {
                if (this.Database.Exists())
                {
                    this.Database.Initialize(true);
                }
            }
            else
            {
                if (!this.Database.Exists())
                {
                    this.Database.Initialize(true);
                }
            }
            return true;
        }

        public void Detach()
        {
            
        }
        public void ReloadData()
        {
            this.Classifications.Load();
            this.FileExtensions.Load();
            this.Templates.Load();
            this.Languages.Include("FileExtensions").Load();
            this.Patterns.Include("Language").Include("Language.FileExtensions").Load();
            this.Categories.Include("Patterns").Include("Template").Include("Classification").Load();
        }

        public T Clone<T>(T entity) where T : BaseEntity
        {
            //this.Configuration.LazyLoadingEnabled = false;
            using (var stream = new System.IO.MemoryStream())
            {

                var entityType = ObjectContext.GetObjectType(entity.GetType());
                var knownTypes = ObjectContext.GetKnownProxyTypes();
                var resolver = new ProxyDataContractResolver();
                var serializer = new DataContractSerializer(
                               entityType,
                               entityType.Name,
                               string.Empty,
                               knownTypes,
                               100, true, true,
                               null, resolver);

                serializer.WriteObject(stream, entity);
                stream.Position = 0;
                return (T)serializer.ReadObject(stream);
            }
        }


        private void ForEachDbSet(Action<DbSet> set)
        {
            foreach (PropertyInfo pi in this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                object value = pi.GetValue(this, null);
                if (value is DbSet)
                {
                    set(value as DbSet);
                }
            }
        }

    }
    public class DatabaseContextInitializer : DropCreateDatabaseAlways<DatabaseContext>
    {
        private void SeedDefaultLanguages(DatabaseContext context)
        {
             //All
            Language lang = context.Languages.Create();
            lang.Name = "All";
            FileExtension ext = context.FileExtensions.Create();
            ext.Extension = ".*";
            FileExtension wildCard = ext;

            lang.FileExtensions.Add(ext);
            context.FileExtensions.Add(ext);
            context.Languages.Add(lang); 

            //Misc
            lang = context.Languages.Create();
            lang.Name = "Misc";

            ext = context.FileExtensions.Create();
            ext.Extension = ".txt";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".xml";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            context.Languages.Add(lang); 


            //C
            lang = context.Languages.Create();
            lang.Name = "C/C++";

            ext = context.FileExtensions.Create();
            ext.Extension = ".c";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".cpp";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".cxx";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".hpp";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".hxx";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            context.Languages.Add(lang); 

            //C#

            lang = context.Languages.Create();
            lang.Name = ".Net";

            ext = context.FileExtensions.Create();
            ext.Extension = ".cs";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".xaml";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);


            //Razor views ASP .Net 2/3
            ext = context.FileExtensions.Create();
            ext.Extension = ".cshtml";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);


            ext = context.FileExtensions.Create();
            ext.Extension = ".aspx";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".ps1";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);
            
            ext = context.FileExtensions.Create();
            ext.Extension = ".psm1";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".asmx";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".ascx";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".ashx";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".asp";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".vb";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".vbs";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".config";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            //Azure Config files
            //cscfg
            //csdef
            ext = context.FileExtensions.Create();
            ext.Extension = ".csdef";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);


            ext = context.FileExtensions.Create();
            ext.Extension = ".cscfg";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            context.Languages.Add(lang); 


            //Ruby

            lang = context.Languages.Create();
            lang.Name = "Ruby";


            ext = context.FileExtensions.Create();
            ext.Extension = ".rb";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            context.Languages.Add(lang); 
            
            //Java
            lang = context.Languages.Create();
            lang.Name = "Java";

        

            ext = context.FileExtensions.Create();
            ext.Extension = ".java";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".jsp";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            context.Languages.Add(lang); 

            //Python
            lang = context.Languages.Create();
            lang.Name = "Python";

           

            ext = context.FileExtensions.Create();
            ext.Extension = ".py";
            lang.FileExtensions.Add(ext);
            context.FileExtensions.Add(ext);

            context.Languages.Add(lang); 

            //Perl
            lang = context.Languages.Create();
            lang.Name = "Perl";

        
 
            ext = context.FileExtensions.Create();
            ext.Extension = ".pl";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            context.Languages.Add(lang); 
            //Html/Javascript
            lang = context.Languages.Create();
            lang.Name = "Html";

          

            ext = context.FileExtensions.Create();
            ext.Extension = ".html";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".htm";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            context.Languages.Add(lang); 
            //Javascript
            lang = context.Languages.Create();
            lang.Name = "Javascript";

            ext = context.FileExtensions.Create();
            ext.Extension = ".js";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Local.FirstOrDefault((x) => x.Extension == ".html");
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Local.FirstOrDefault((x) => x.Extension == ".htm");
            lang.FileExtensions.Add(ext);

            context.Languages.Add(lang); 

            //CSS
            lang = context.Languages.Create();
            lang.Name = "CSS";


            ext = context.FileExtensions.Local.FirstOrDefault((x) => x.Extension == ".html");
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Local.FirstOrDefault((x) => x.Extension == ".htm");
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Create();
            ext.Extension = ".css";
            context.FileExtensions.Add(ext);
            lang.FileExtensions.Add(ext);

            context.Languages.Add(lang);

            lang = context.Languages.Create();
            lang.Name = "All File Types"; //If this name changes it will break stuffs. Need to make sure this doesnt show up in the Manage ViewModel. 
            lang.FileExtensions.Add(new FileExtension() { Extension = ".exe" });
            lang.FileExtensions.Add(new FileExtension() { Extension = ".com" });
            lang.FileExtensions.Add(new FileExtension() { Extension = ".dll" });
            lang.FileExtensions.Add(new FileExtension() { Extension = ".zip" });
            lang.FileExtensions.Add(new FileExtension() { Extension = ".iso" });
            lang.FileExtensions.Add(new FileExtension() { Extension = ".rar" });
            lang.FileExtensions.Add(new FileExtension() { Extension = ".7z" });
            lang.FileExtensions.Add(new FileExtension() { Extension = ".jpg" });
            lang.FileExtensions.Add(new FileExtension() { Extension = ".bmp" });
            lang.FileExtensions.Add(new FileExtension() { Extension = ".gif" });

            context.Languages.Add(lang);

            //Powershell
            lang = context.Languages.Create();
            lang.Name = "PowerShell";


            ext = context.FileExtensions.Local.FirstOrDefault((x) => x.Extension == ".ps1");
            lang.FileExtensions.Add(ext);

            ext = context.FileExtensions.Local.FirstOrDefault((x) => x.Extension == ".psm1");
            lang.FileExtensions.Add(ext);
            context.Languages.Add(lang);

           
        }

        private List<String> GetAllLinesFromFile(String fileName)
        {
            List<String> ret = new List<string>(); 
            var sr = new System.IO.StreamReader(System.IO.File.Open(fileName, System.IO.FileMode.Open));
            while (!sr.EndOfStream)
            {
                ret.Add(sr.ReadLine());
            }
            return ret;
        }
        
        private void LoadDefaultTemplates(DatabaseContext context)
        {
            Template t = new Template();
            t.RawTemplate = Models.TemplateTransformationModel.DEFAULT_TEMPLATE;
            t.Name = "DEFAULT_TEMPLATE";
            t.IsSingularOnly = false;
            t.Id = new Guid("00000000-0000-0000-0000-000000000001"); 

            context.Templates.Add(t); 
        }
        protected override void Seed(DatabaseContext context)
        {
            context.Configuration.LazyLoadingEnabled = false;

            SeedDefaultLanguages(context);
            context.SaveChanges();

            LoadDefaultTemplates(context);
            context.SaveChanges(); 

       

            context.SaveChanges(); 
        }
    }
}
 